/**
 * Copyright (C), 2015-2018
 * FileName: FilterConfiguration
 * Author:   Dayu Hou
 * Date:     2018/1/10 11:38
 * Description:
 * History:
 * <author>          <time>         <desc>
 */
package com.apache.tomcat;

import com.apache.client.common.TokenInterceptor;
import com.apache.ius.common.annotion.AnnotationUtil;
import com.apache.ius.listener.IusParamsListener;
import com.apache.passport.common.JwtClientFilter;
import com.apache.portal.common.restfull.ResultFullFilter;
import com.apache.portal.contorller.UploadServlet;
import com.apache.rpc.StartSocketPortListener;
import com.apache.rpc.common.RpcUtil;
import com.apache.tools.PropertiesConfig;
import com.apache.tools.StrUtil;
import com.apache.uct.common.filter.LicenseFilter;
import org.apache.catalina.connector.Connector;
import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.ajp.AjpNioProtocol;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.http.LegacyCookieProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.nio.charset.Charset;
import java.util.EventListener;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author Dayu Hou
 * @since 1.0.0
 */
@Configuration
public class FilterConfiguration extends WebMvcConfigurerAdapter {

    @Autowired
    private Environment env;

    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TokenInterceptor("ius")).addPathPatterns("/**");
        super.addInterceptors(registry);
    }

    @Bean
    public StartSocketPortListener startSocketPortListener() {
        String socketPort = StrUtil.doNull(env.getProperty("rpc.service.port"), "20808");
        StartSocketPortListener listener = new StartSocketPortListener(socketPort);
        if (StrUtil.isNotNull(env.getProperty("rpc.version"))) {
            RpcUtil.getInstance().setVersion(env.getProperty("rpc.version"));
        }
        //自动扫描包(拦截器专用)
        AnnotationUtil.getInstance().loadCalssBean("com.apache.ius");
        return listener;
    }

    /**
     * 加载listener
     */
    @Bean
    public ServletListenerRegistrationBean<EventListener> getDemoListener() {
        ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<>();
        registrationBean.setListener(new IusParamsListener());
        registrationBean.setOrder(2);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean encodingFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CharacterEncodingFilter());
        registration.addUrlPatterns("/*");
        registration.addInitParameter("encoding", "UTF-8");
        registration.addInitParameter("forceEncoding", "true");
        registration.setName("encodingFilter");
        registration.setOrder(1);
        return registration;
    }

    @Bean
    public FilterRegistrationBean defaultBaseSecurityFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new LicenseFilter());
        registration.addUrlPatterns("/*");
        registration.setName("licenseFilter");
        registration.setOrder(2);
        return registration;
    }

    @Bean
    public FilterRegistrationBean ssoClientFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new JwtClientFilter());
        registration.addUrlPatterns("/*");
        registration.setName("ssoClientFilter");
        registration.addInitParameter("sysCode", "ius");//指定白名单
        //registration.addInitParameter("loginUrl",env.getProperty("server.loginUrl"));
        registration.setOrder(2);
        return registration;
    }

    @Bean
    public FilterRegistrationBean resultFullFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new ResultFullFilter());
        registration.addUrlPatterns("/common/coding/*","/trans/template/*","/res/uct/*");//多个英文逗号隔开
        registration.setName("resultFullFilter");
        registration.addInitParameter("servletPackage", "com.apache.portal");
        registration.setOrder(3);
        return registration;
    }

    @Bean
    public ServletRegistrationBean getServletRegistrationBean() {  //一定要返回ServletRegistrationBean
        ServletRegistrationBean bean = new ServletRegistrationBean(new UploadServlet());     //放入自己的Servlet对象实例
        bean.addUrlMappings("/uploadServlet");  //访问路径值
        return bean;
    }

    //注入文件验证码servlet
    /*@Bean
    public ServletRegistrationBean getRandCodeImageServlet() {  //一定要返回ServletRegistrationBean
        ServletRegistrationBean bean = new ServletRegistrationBean(new RandCodeImageServlet(), "/web/CheckRandCode");
        return bean;
    }*/

  /**
     * 自定义tomcat初始化工厂
     */
    @Bean
    public TomcatServletWebServerFactory createEmbeddedServletContainerFactory() {
        PropertiesConfig.setApplicatinConfig(env);
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.setUriEncoding(Charset.forName("UTF-8"));
        tomcat.setPort(Integer.parseInt(doNull(env.getProperty("spring.tomcat.port"), "8080")));
        tomcat.addConnectorCustomizers(new MyTomcatConnectorCustomizer());
        if (StrUtil.isNotNull(env.getProperty("spring.tomcat.ajp.port"))) {
            tomcat.addAdditionalTomcatConnectors(createAjpConnector());//createSslConnector(),
        }
        return tomcat;
    }

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
        return (factory) -> factory.addContextCustomizers((context) -> context.setCookieProcessor(new LegacyCookieProcessor()));
    }

    /**
     * ajp配置
     */
    private Connector createAjpConnector() {
        Connector connector = new Connector("org.apache.coyote.ajp.AjpNioProtocol");
        AjpNioProtocol protocol = (AjpNioProtocol) connector.getProtocolHandler();
        connector.setScheme("http");
        protocol.setSecretRequired(false);
        connector.setPort(Integer.parseInt(doNull(env.getProperty("spring.tomcat.ajp.port"), "8009")));
        protocol.setPacketSize(Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxHttpHeaderSize"), "28192")));
        setHttpParams(protocol);
        return connector;
    }

    /**
     * 设置优化参数
     */
    private void setHttpParams(AbstractProtocol protocol) {
        //在任何给定的时间内，服务器将接受和处理的最大连接数
        protocol.setMaxConnections(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxConnections"), "10000")));
        //设置最大线程数，如果未配置默认值为200
        protocol.setMaxThreads(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxThreads"), "200")));
        //minSpareThreads：线程的最小运行数目，这些始终保持运行。如果未指定，默认值为10
        protocol.setMinSpareThreads(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.minSpareThreads"), "10")));
        //当请求已经被接受，但未被处理，也就是等待中的超时时间。单位为毫秒，默认值为60000
        protocol.setConnectionTimeout(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.timeOut"), "60000")));
        //当所有可能的请求处理线程都在使用时传入连接请求的最大队列长度，默认值为100
        protocol.setAcceptCount(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.acceptCount"), "200")));
    }

    private String doNull(String str, String defaultStr) {
        if (isNull(str)) {
            return defaultStr;
        }
        return str;
    }

    private boolean isNull(String str) {
        boolean mark = false;
        if (null == str || str.trim().equals("") || str.trim().equalsIgnoreCase("null")) {
            mark = true;
        }
        return mark;
    }

    class MyTomcatConnectorCustomizer implements TomcatConnectorCustomizer {

        public void customize(Connector connector) {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            protocol.setMaxHttpHeaderSize(Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxHttpHeaderSize"), "28192")));
            setHttpParams(protocol);
        }
    }

}